package com.project.shiro.filter;

import com.project.myBeans.ConfigParameters;
import com.project.service.base.CacheService;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import net.sf.json.JSONObject;
import org.apache.log4j.Logger;
import org.apache.shiro.web.filter.authc.AuthenticationFilter;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by TAO on 2016/3/25.
 */
//shiro 自定义拦截器/过滤器

public class MobileTokenAuthenticationFilter extends AuthenticationFilter {
    @Autowired
    private CacheService cacheService;

    @Autowired
    private ConfigParameters configParameters;

    private static final String TOKEN = "token";

    private Jws jws;

    protected Logger log = Logger.getLogger(getClass());

    /**
      * 约定：app端在请求API时，在RequestHeaders上都要附加上token
      */

    /**
     * 拦截器配置为anon的URI，不会执行onAccessDenied（）方法；
     * 其它URI，则会执行onAccessDenied（）方法；
     */
    public boolean isAccessAllowed(ServletRequest request,  ServletResponse response, Object mappedValue) {

//        return false; //返回false，才会执行onAccessDenied（）方法；
        return true;  //app测试阶段，返回true
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) {

        log.info("app 用户进入校验！" );

        HttpServletRequest req = (HttpServletRequest) request;

        String token=req.getHeader(TOKEN);

        //=== 列出所有headers
//        Enumeration headerNames = ((HttpServletRequest) request).getHeaderNames();
//        while (headerNames.hasMoreElements()) {
//            String key = (String) headerNames.nextElement();
//            String value = ((HttpServletRequest) request).getHeader(key);
//            System.out.println(key+"=="+value);
//        }
        //===

        System.out.println("appFilter token>>>>>>" + token);

        if (isAccess(token)) {
            return onAccessSuccess(req, (HttpServletResponse) response);
        }

        return onAccessFail(req, (HttpServletResponse) response);
    }

    /**
     * 判断token的合法性
     * @param token
     * @return
     */
    public   boolean isAccess(String token){

        if(token==null||token=="")
            return false;

        //验证token
        String key=configParameters.getJwtAppTokenSecret();

        try {

            jws = Jwts.parser().setSigningKey(key).parseClaimsJws(token); //验证token

            //OK, we can trust this JWT
//            System.out.println("ok1:" + jws.getBody()); //{sub=Joe, iss=userId, exp=1458906942}
//            System.out.println("ok2:" + jsonObject.get("iss"));

        } catch (Exception e) {
            //don't trust the JWT! 发生异常，则token验证不成功
            return false;
        }
        return true;
    }

    /**
     * 认证成功进行的操作处理
     *
     * @param request
     * @param response
     * @return true 继续后续处理，false 不需要后续处理
     */
     public  boolean onAccessSuccess(HttpServletRequest request, HttpServletResponse response )
     {
         /**
          * refresh_token：利用token超时时间，计算一下剩余时间，剩余时间小于1分钟
          * 开始核发新的token，客户端自动使用新的token，等退出时，就不核发新的token。
          */
         String key=configParameters.getJwtAppTokenSecret();
         Long expirationTime=System.currentTimeMillis()+configParameters.getAppTokenValidTime()*1000;
         DateTime dt = new DateTime();

         JSONObject jsonObject= JSONObject.fromObject(jws.getBody());
         Long exp=Long.valueOf(jsonObject.get("exp").toString())*1000; //token过期时间，转成毫秒

         if((exp-System.currentTimeMillis())<60*1000) //核发新的token
         {
             String token = Jwts.builder()         //创建token
                     .setIssuer(jsonObject.get("iss").toString())
                     .setExpiration(dt.plusSeconds(configParameters.getAppTokenValidTime()).toDate())
                     .signWith(SignatureAlgorithm.HS512, key)
                     .compact();
            response.setHeader("refresh_token",token); //app端获取token，判断token不为空，则登录成功，否则 登录失败
            response.setHeader("expires",expirationTime.toString());
            response.setHeader("isRefreshToken","true"); //核发新的token
         }
         else
             response.setHeader("isRefreshToken","false");

         response.setHeader("isTokenValidity", "true"); //token有效

         return true;
     }

    /**
     * 认证失败时处理结果
     *
     * @param request
     * @param response
     * @return true 继续后续处理，false 不需要后续处理
     */
    public boolean onAccessFail(HttpServletRequest request,HttpServletResponse response){

        JSONObject result=new JSONObject();
        result.put("msg", "token无效或过期");
        try {
            response.setHeader("isTokenValidity", "false"); //token无效或过期
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); //status: 401
            response.getWriter().write(result.toString()); //输出response到客户端
        }catch (Exception e)
        {
        }

        return false;
    }

}
